
//
// 110401 - AH - Created.
// 110402 - AH - (Zen *) isCue(String).
// 110403a- AH - Changed from using StringTokenizer to StreamTokenizer so can
//               handle " quoted sub strings.
// 110403b- AH - passedEnd(int).
// 110404 - AH - (Fotballpuben *) Made '*' an 'ordinary' character so *be can 
//               be parsed.
// 110412a- AH - Removed commented away code, the use of StreamTokenize, now
//               is using my own Tokenizer and simple main test program.
// 110412b- AH - getTokensTo(int, List<String>, String...).
// 110412c- AH - Renamed getToken to look, more in the spirit of parsing.
// 120321 - AH - Removed @Override for interface method (1.5 compatible).
//

package org.soekrat.engine.pitbul.parser;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.soekrat.engine.util.Util;

/**
 * <p>
 *   Represents parsed text of the Pitbul language, what comes between '{' and
 *   '}'.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC) 
 */
public final class PitbulTokens implements Iterable<String> 
{
  private List<String> m_tokens=new ArrayList<String>();
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param txt Text to parse.
   */
  public PitbulTokens(String txt)
  {
    if (txt==null)
    {
      throw new NullPointerException("txt");
    }
    
    TokenizerOld tokenizer=new TokenizerOld(txt);
    String token=tokenizer.next();
    while (token!=null)
    {
      m_tokens.add(token);
      token=tokenizer.next();
    }
  }
  
  /**
   * <p>
   *   Gets number of tokens.
   * </p>
   * @return Count.
   */
  public int size(){ return m_tokens.size(); }
  
  /**
   * <p>
   *   Gets token.
   * </p>
   * @param idx Index of token.
   * @return Token.
   * @throws IndexOutOfBoundsException If {@code idx<0 || idx>=size()}.
   */
  public String look(int idx){ return m_tokens.get(idx); }
  
  /**
   * <p>
   *   Tells if index is past index of last token.
   * </p>
   * @param idx Index.
   * @return {@code idx>=size()}.
   * @throws IllegalArgumentException If {@code idx<0}.
   */
  public boolean passedEnd(int idx)
  {
    if (idx<0)
    {
      throw new IndexOutOfBoundsException(Integer.toString(idx));
    }
    
    return idx>=size();
  }
  
  /**
   * <p>
   *   Gets the first token, this is the <i>form</i>.
   * </p>
   * @return Token.
   */
  public String getForm(){ return m_tokens.get(0); }
  
  /**
   * <p>
   *   Tells if next tokens matches a given sequence.
   * </p>
   * @param from      Index to current token.
   * @param sequence Tokens in sequence.
   * @return {@code true} match sequence {@code false} if does not.
   */
  protected boolean match(int from, String... match)
  {
    if (from<0)
    {
      throw new IndexOutOfBoundsException("idx<0 : "+from);  
    }
    
    int n=m_tokens.size();
    int nm1=n-1;
    int m=match.length;
    
    if (from>=n-1) return false;
    
    for (int i=0; i<m; i++)
    {
      if (from==nm1) return false;
      String expected=match[i];
      String curr=m_tokens.get(from++);
      if (!curr.equals(expected)) return false;
    }
    
    return true;
  }
  
  /**
   * <p>
   *   Gets tokens from (including) to one of given tokens are encountered or
   *   end of tokens.
   * </p>
   * @param from Index to start scan from.
   * @param to   Tokens that mark end of scan, encountered 'to' token is not 
   *             returned.
   * @return Index to the next token or passed tokens if all read.
   */
  public int getTokensTo(int from, List<String> tokens, String... to)
  {
    int n=m_tokens.size();
    boolean done=false;
    while (from<n && !done)
    {
      String t=m_tokens.get(from++);
      if (!Util.contains(to, t)) 
      {
        tokens.add(t);
      }
      else
      {
        done=true;
      }
    }
    return from;
  }

  // Declared in Iterable<String>
  public Iterator<String> iterator(){ return m_tokens.iterator(); }
  
  @Override
  public String toString(){ return m_tokens.toString();  }
  
  /**
   * <p>
   *   Tells if token is a cue.
   * </p>
   * @param token Token.
   * @return {@code true} if is, {@code false} if is not.
   */
  public static boolean isCue(String token)
  {
    if (token==null)
    {
      throw new NullPointerException("token");
    }
    
    return token.length()>1 && token.charAt(0)=='#' && 
      Character.isLetter(token.charAt(1));
  }
  
}
